/**
 * @(#)CompensadorManagerK.java Feb 21, 2007
 *
 * Copyright (c) 2005-2010 Psiqueware S.A. de C.V. All Rights Reserved.
 * This software is the proprietary information Psiqueware S.A. de C.V.
 * Use is subject to license terms.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
 * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
 * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 *
 * <br/>Usuario : Psique
 * <br/>Creaci&oacute;n: Feb 21, 2007 - 10:32:19 AM
 * <br/>
 * <br/>
 * <br/><t5>Cambios :</t5>
 * <br/><b>Fecha | Autor  |  Cambios</b>
 * <ul>
 * <li>Feb 21, 2007 | <a href = "mailto:AngelElectrico@PsiqueWare.com">Psique</a> | Creaci&oacute;n del Objeto.</li>
 * <li>Abr 19, 2007 | <a href = "mailto:AngelElectrico@PsiqueWare.com">Psique</a> | Se eliminar&oacute;n las referencias a las clases Empresa, Deportamento, etc y se cambiar&oacute;n por referencias a Estructura.</li>
 *
 * </ul>
 */

package com.psiqueware.jazmin.empresas.recursos.humanos.compensaciones.manager;

import com.psiqueware.alheli.exception.NotNullConditionException;
import com.psiqueware.alheli.exception.NullArgumentException;
import com.psiqueware.alheli.dao.EnlaceTransaccional;
import com.psiqueware.alheli.manager.BaseManager;
import com.psiqueware.alheli.manager.ManagerException;
import com.psiqueware.alheli.logging.Logger;
import com.psiqueware.alheli.logging.LoggerFactory;
import com.psiqueware.alheli.seguridad.Llave;
import com.psiqueware.alheli.seguridad.Modulo;
import com.psiqueware.alheli.seguridad.SeguridadManagerFactory;
import com.psiqueware.alheli.seguridad.UsuariosSeguridadManager;
import com.psiqueware.jazmin.empresas.recursos.humanos.Asignacion;
import com.psiqueware.jazmin.empresas.recursos.humanos.Empleado;
import com.psiqueware.jazmin.empresas.recursos.humanos.compensaciones.CompensadorManager;
import com.psiqueware.jazmin.empresas.recursos.humanos.compensaciones.EstructuraSalarial;
import com.psiqueware.jazmin.empresas.recursos.humanos.compensaciones.GradoRangoSalarial;
import com.psiqueware.jazmin.empresas.recursos.humanos.compensaciones.Incremento;
import com.psiqueware.jazmin.empresas.recursos.humanos.compensaciones.IncrementoPropuesto;
import com.psiqueware.jazmin.empresas.recursos.humanos.compensaciones.RegistroEmpleado;
import com.psiqueware.jazmin.empresas.recursos.humanos.compensaciones.dao.CompensacionesDAOFactory;
import com.psiqueware.jazmin.empresas.recursos.humanos.compensaciones.dao.EstructuraSalarialDAO;
import com.psiqueware.jazmin.empresas.recursos.humanos.compensaciones.dao.GradoRangoSalarialDAO;
import com.psiqueware.jazmin.empresas.recursos.humanos.compensaciones.dao.IncrementoPropuestoDAO;
import com.psiqueware.jazmin.empresas.recursos.humanos.compensaciones.dao.RegistroEmpleadoDAO;
import com.psiqueware.jazmin.empresas.recursos.humanos.compensaciones.modelo.EstructuraSalarialK;
import com.psiqueware.jazmin.empresas.recursos.humanos.compensaciones.modelo.GradoRangoSalarialK;
import com.psiqueware.jazmin.empresas.recursos.humanos.compensaciones.modelo.IncrementoPropuestoK;
import com.psiqueware.jazmin.empresas.recursos.humanos.compensaciones.modelo.RegistroEmpleadoK;
import com.psiqueware.tulipan.organizacional.Estructura;

import java.math.BigDecimal;
import java.util.Collections;
import java.util.List;

/**
 * Encargado de la operaciones de compensaciones de los empleados.
 * <br/>Paquete Original: com.psiqueware.laVIE.empresas.empleados.compensaciones.manager
 * <br/>Nombre  Original: CompensadorManagerK
 * <br/>Oprima para ver : <a href="CompensadorManagerK.java.html"><i>C&oacute;digo Fuente</i> </a>
 *
 * @author <a href="mailto:AngelElectrico@PsiqueWare.com">Psique</a>
 * @version Revision: 1.1 Feb 21, 2007 10:32:19 AM
 * @noinspection CastToConcreteClass,FeatureEnvy,DuplicateStringLiteralInspection,OverlyCoupledClass,ClassWithoutToString
 */
public class CompensadorManagerK extends BaseManager implements Modulo, CompensadorManager
{

    /** Logger de clase para CompensadorManagerK */
    private static final Logger s_log = LoggerFactory.getLogger ( CompensadorManagerK.class );

    /** DAO de {@link EstructuraSalarial}. */
    private static EstructuraSalarialDAO s_EstructuraSalarialDAO = CompensacionesDAOFactory.findDAOEstructuraSalarial ();

    /** DAO de {@link GradoRangoSalarial}. */
    private static GradoRangoSalarialDAO s_GradoRangoSalarialDAO = CompensacionesDAOFactory.findDAOGradoRangoSalarial ();

    /** DAO de {@link RegistroEmpleado}. */
    private static RegistroEmpleadoDAO s_RegistroEmpleadoDAO = CompensacionesDAOFactory.findDAORegistroEmpleado ();

    /** DAO de {@link IncrementoPropuesto}. */
    private static IncrementoPropuestoDAO s_IncrementoPropuestoDAO = CompensacionesDAOFactory.findDAOIncrementoPropuesto ();

    /** Llave de Seguridad de Compensaciones. */
    private Llave m_llave;

    /** Manager para el registro de la seguridad. */
    private static UsuariosSeguridadManager s_m_UsuariosSeguridadManager = SeguridadManagerFactory.getUsuariosSeguridadManager ();

    /** Constructor de CompensadorManagerK. */
    public CompensadorManagerK ()
    {
    }





    /**
     * Propone un {@link Incremento} para un {@link RegistroEmpleado}.
     * <p/>
     * Es necesario que no se tenga un {@link IncrementoPropuesto} de gerente
     * ya en el {@link RegistroEmpleado}; si se tiene el m&eacute;todo devolver&aacute; <code>null</code>.
     *
     * @param registroEmpleado    {@link RegistroEmpleado} donde se pretende proponer el {@link Incremento}.
     * @param incremento          propuesto.
     * @param gerente             que autoriza la transacci&oacute;n.  Si no tiene la seguridad inicializada el m&eacute;todo la inicializa.
     * @param enlaceTransaccional para asegurar la atomicidad de la transacci&oacute;n.
     *
     * @return el {@link IncrementoPropuesto} en caso de poderse proponer; <code>null</code> en caso contrario.
     *
     * @throws ManagerException en caso de no poder completar la operaci&oacute;n.
     */
    public IncrementoPropuesto proponerIncremento ( RegistroEmpleado registroEmpleado, Incremento incremento, Empleado gerente, EnlaceTransaccional enlaceTransaccional ) throws ManagerException
    {
        try
        {
            //validamos
            if ( null == registroEmpleado ) throw new NullArgumentException ( "<error>El argumento 'registroEmpleado' no puede ser NULL.</error>" );
            if ( null == registroEmpleado.getId () ) throw new IllegalArgumentException ( "<error>El argumento 'registroEmpleado' deb&iacute;a encontrarse previamente persistido.</error>" );
            if ( null == gerente ) throw new NullArgumentException( "<error>El argumento 'gerente' no puede ser NULL.</error>" );
            if ( null == gerente.getId () ) throw new IllegalArgumentException ( "<error>El argumento 'gerente' deb&iacute;a encontrarse previamente persistido.</error>" );
            if ( null != registroEmpleado.getAumentoGerente () ) throw new NotNullConditionException ( "<error>El atributo 'registroEmpleado.getAumentoGerente ()' deb&iacute;a ser NULL para que esta operaci&oacute;n sea v&aacute;lida.</error>" );

            //si el gerente no tiene la seguridad inicializada, la iniciamos.
            if ( null == gerente.getCargo ().getCredencial () ) s_m_UsuariosSeguridadManager.iniciarSeguridadUsuario ( gerente.getCargo (), enlaceTransaccional );

            //Verificamos que el gerente este habilitado para incrementar sueldos
            IncrementoPropuestoK incrementoPropuesto = null;
            if ( m_llave.isHabilitadoActividad ( m_incrementarSueldo, gerente.getCargo () ) )
            {
                incrementoPropuesto = new IncrementoPropuestoK ( incremento );
                incrementoPropuesto.setClavePropuestoPor ( gerente.getClave () );
                s_IncrementoPropuestoDAO.saveIncrementoPropuesto ( incrementoPropuesto, enlaceTransaccional );
                RegistroEmpleadoK registroEmpleadoK = ( RegistroEmpleadoK ) registroEmpleado;
                registroEmpleadoK.setAumentoGerente ( incrementoPropuesto );
                s_RegistroEmpleadoDAO.updateRegistroEmpleado ( registroEmpleadoK, enlaceTransaccional );
            }
            return incrementoPropuesto;

        }
        catch ( Exception e )
        {
            final String error = "<error><msg>No se pudo proponer un incremento.</msg><parametros></parametros></error>";
            s_log.error ( error );
            s_log.error ( e );
            enlaceTransaccional.rollBack ();
            throw new RuntimeException ( error, e );
        }
    }

    /**
     * Genera un {@link RegistroEmpleado} para la {@link Asignacion} y {@link EstructuraSalarial} dada.
     *
     * @param asignacion          a la cual obedece actualmente el {@link Empleado}.
     * @param estructuraSalarial  que tiene asignado.
     * @param enlaceTransaccional para asegurar la atomicidad de la transacci&oacute;n.
     *
     * @return nuevo {@link RegistroEmpleado} para el {@link Empleado} de la {@link Asignacion}.
     *
     * @throws ManagerException en caso de no poder completar la operaci&oacute;n.
     */
    public RegistroEmpleado registraEmpleado ( Asignacion asignacion, EstructuraSalarial estructuraSalarial, EnlaceTransaccional enlaceTransaccional ) throws ManagerException
    {
        try
        {
            if ( null == asignacion ) throw new NullArgumentException ( "<error>El argumento 'asignacion' no puede ser NULL.</error>" );
            if ( null == asignacion.getId () ) throw new IllegalArgumentException ( "<error>El argumento 'asignacion' deb&iacute;a encontrarse previamente persistido.</error>" );
            if ( null == estructuraSalarial ) throw new NullArgumentException ( "<error>El argumento 'estructuraSalarial' no puede ser NULL.</error>" );
            if ( null == estructuraSalarial.getId () ) throw new IllegalArgumentException ( "<error>El argumento 'estructuraSalarial' deb&iacute;a encontrarse previamente persistido.</error>" );
            final Empleado empleado = asignacion.getEmpleado ();
            if ( null == empleado ) throw new NullArgumentException ( "<error>El argumento 'empleado' no puede ser NULL.</error>" );
            if ( null == empleado.getId () ) throw new IllegalArgumentException ( "<error>El argumento 'empleado' deb&iacute;a encontrarse previamente persistido.</error>" );

            RegistroEmpleado ultimo = s_RegistroEmpleadoDAO.findUltimoRegistroPorEmpleado ( empleado, enlaceTransaccional );

            RegistroEmpleadoK registroEmpleadoK = new RegistroEmpleadoK ( ultimo, asignacion, estructuraSalarial );
            return s_RegistroEmpleadoDAO.saveRegistroEmpleado ( registroEmpleadoK, enlaceTransaccional );
        }
        catch ( Exception e )
        {
            final String error = "<error><msg>No se pudo realizar un registro</msg><parametros>" + asignacion + "</parametros></error>";
            s_log.error ( error );
            s_log.error ( e );
            enlaceTransaccional.rollBack ();
            throw new ManagerException ( error, e );

        }
    }

    /**
     * Da de alta una nueva {@link EstructuraSalarial} para la Empresa dada.
     *
     * @param estructura             Empresa a la que pertenecer&aacute; la {@link EstructuraSalarial}.
     * @param clave               para identificarla de otras estructuras.
     * @param enlaceTransaccional para asegurar la atomicidad de la transacci&oacute;n.
     *
     * @return {@link EstructuraSalarial} nueva.
     *
     * @throws ManagerException en caso de no poder completar la operaci&oacute;n.
     */
    public EstructuraSalarial nuevaEstructuraSalarial ( Estructura estructura, String clave, EnlaceTransaccional enlaceTransaccional ) throws ManagerException
    {
        try
        {
            //validamos
            if ( null == estructura ) throw new NullArgumentException ( "<error>El argumento 'estructura' no puede ser NULL.</error>" );
            if ( null == estructura.getId () ) throw new IllegalArgumentException ( "<error>El argumento 'estructura' deb&iacute;a encontrarse previamente persistido.</error>" );
            if ( null == clave ) throw new NullArgumentException ( "<error>El argumento 'clave' no puede ser NULL.</error>" );
            //verificamos que no existan estructuras de la misma clave para esta estructura.
            if ( s_EstructuraSalarialDAO.existeEstructuraSalarialPorClaveIdEstructura ( clave, estructura ) ) throw new IllegalArgumentException ( "<error>Ya existe una EstructuraSalarial con la clave '" + clave + "' para la estructura: " + estructura.getId () + "</error>" );
            //creamos
            EstructuraSalarialK estructuraSalarial = new EstructuraSalarialK ( estructura, clave );
            //salvamos
            return s_EstructuraSalarialDAO.saveEstructuraSalarial ( estructuraSalarial, enlaceTransaccional );
        }
        catch ( Exception e )
        {
            final String error = "<error><msg>No se pudo crear la nueva EstructuraSalarial</msg><parametros>" + clave + "</parametros></error>";
            s_log.error ( error );
            s_log.error ( e );
            enlaceTransaccional.rollBack ();
            throw new ManagerException ( error, e );
        }
    }

    /**
     * Agrega un nuevo {@link GradoRangoSalarial} a la {@link EstructuraSalarial} dada. Lo ordena y reordena deacuerdo al valor de minimo.
     *
     * @param estructuraSalarial  a la que se le va a agregar el {@link GradoRangoSalarial}.
     * @param clave               para distinguir el {@link GradoRangoSalarial}.
     * @param minimo              del Rango.
     * @param media               del Rango.
     * @param maximo              del Rango.
     * @param enlaceTransaccional para asegurar la atomicidad de la transacci&oacute;n.
     *
     * @return el nuevo {@link GradoRangoSalarial}.
     *
     * @throws ManagerException en caso de no poder completar la operaci&oacute;n.
     * @noinspection OverlyStrongTypeCast,OverlyComplexMethod
     */
    public GradoRangoSalarial agregarGradoRangoSalarial ( EstructuraSalarial estructuraSalarial, String clave, BigDecimal minimo, BigDecimal media, BigDecimal maximo, EnlaceTransaccional enlaceTransaccional ) throws ManagerException
    {
        try
        {
            if ( null == estructuraSalarial ) throw new NullArgumentException ( "<error>El argumento 'estructuraSalarial' no puede ser NULL.</error>" );
            if ( null == estructuraSalarial.getId () ) throw new IllegalArgumentException ( "<error>El argumento 'estructuraSalarial' deb&iacute;a encontrarse previamente persistido.</error>" );
            if ( null == clave ) throw new NullArgumentException ( "<error>El argumento 'clave' no puede ser NULL.</error>" );
            if ( 0 == clave.trim ().length () ) throw new IllegalArgumentException ( "<error>El argumento 'clave' es una cadena vacia.</error>" );
            if ( null == minimo ) throw new NullArgumentException ( "<error>El argumento 'minimo' no puede ser NULL.</error>" );
            if ( null == media ) throw new NullArgumentException ( "<error>El argumento 'media' no puede ser NULL.</error>" );
            if ( null == maximo ) throw new NullArgumentException ( "<error>El argumento 'maximo' no puede ser NULL.</error>" );

            GradoRangoSalarialK gradoRangoSalarialK = new GradoRangoSalarialK ( clave, minimo, media, maximo );
            EstructuraSalarialK eK = ( EstructuraSalarialK ) estructuraSalarial;
            eK.addGradoRangoSalarial ( gradoRangoSalarialK );
            gradoRangoSalarialK.setGrado ( 1 );
            s_GradoRangoSalarialDAO.saveGradoRangoSalarial ( gradoRangoSalarialK, enlaceTransaccional );


            final List<GradoRangoSalarial> list = eK.listGradoRangoSalariales ();
            if ( list.size () > 1 )
            {
                Collections.sort ( list );
                int i = 1;
                for ( GradoRangoSalarial gs : list )
                {
                    GradoRangoSalarialK gsk = ( GradoRangoSalarialK ) gs;
                    gsk.setGrado ( i );
                    i++;
                    s_GradoRangoSalarialDAO.updateGradoRangoSalarial ( gsk, enlaceTransaccional );
                }
            }
            s_EstructuraSalarialDAO.updateEstructuraSalarial ( eK, enlaceTransaccional );

            return gradoRangoSalarialK;
        }
        catch ( Exception e )
        {
            final String error = "<error><msg>No se pudo crear el GradoRangoSalarial.</msg></error>";
            s_log.error ( error );
            s_log.error ( e );
            enlaceTransaccional.rollBack ();
            throw new ManagerException ( error, e );
        }
    }


    /**
     * Establece el Llave de Seguridad de Compensaciones.
     *
     * @param llave nuevo valor para 'llave'.
     *
     * @see Llave
     */
    public void setLlave ( Llave llave )
    {


        m_llave = llave;
    }

    /**
     * Devuelve el Llave de Seguridad de Compensaciones.
     *
     * @return valor de 'llave'.
     *
     * @see Llave
     */
    public Llave getLlave ()
    {
        return m_llave;
    }
}

